package com.facebook.app.client;

import java.util.List;

import com.facebook.app.client.event.ActionFailedEvent;
import com.facebook.app.client.event.ActionFailedEventHandler;
import com.facebook.app.client.event.ClusterStrategyChosenEvent;
import com.facebook.app.client.event.ClusterStrategyChosenEventHandler;
import com.facebook.app.client.event.ClusteringEndedEvent;
import com.facebook.app.client.event.ClusteringEndedEventHandler;
import com.facebook.app.client.event.ReadyForClusteringEvent;
import com.facebook.app.client.event.ReadyForClusteringEventHandler;
import com.facebook.app.client.presenter.ClusterStrategyChoicePresenter;
import com.facebook.app.client.presenter.ClusterStrategyChosenPresenter;
import com.facebook.app.client.presenter.ClusteringEndedPresenter;
import com.facebook.app.client.presenter.Presenter;
import com.facebook.app.client.presenter.ReadyForClusteringPresenter;
import com.facebook.app.client.view.ClusterStrategyChoiceView;
import com.facebook.app.client.view.ClusterStrategyChosenView;
import com.facebook.app.client.view.ClusteringEndedView;
import com.facebook.app.client.view.ReadyForClusteringView;
import com.facebook.app.shared.clustering.Clusterable;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HasWidgets;

public class AppController implements Presenter, ValueChangeHandler<String> {
	
	private final FacebookServiceAsync rpcService;
	private final HandlerManager eventBus;
	private HasWidgets container;
	private final String accessToken;
	
	private ClusteringMethod selectedClusteringMethod;
	
	private List<Clusterable> clusterElements;
	private List<Clusterable> clusteringResults;
	
	public AppController(FacebookServiceAsync rpcService, HandlerManager eventBus, String accessToken) {
		this.rpcService = rpcService;
		this.eventBus = eventBus;
		this.accessToken = accessToken;
		bind();
	}
	
	private void bind() {
		
		History.addValueChangeHandler(this);
		
		eventBus.addHandler(ClusterStrategyChosenEvent.TYPE, new ClusterStrategyChosenEventHandler() {
			@Override
			public void onClusterStrategyChosen(ClusterStrategyChosenEvent event) {
				doClusterStrategyChosen(event.getClusteringMethod());
			}
		});
		
		eventBus.addHandler(ReadyForClusteringEvent.TYPE, new ReadyForClusteringEventHandler() {
			@Override
			public void onReadyForClustering(ReadyForClusteringEvent event) {
				doReadyForClustering(event.getClusterElements());
			}
		});
		
		eventBus.addHandler(ClusteringEndedEvent.TYPE, new ClusteringEndedEventHandler() {
			@Override
			public void onClusteringEnded(ClusteringEndedEvent event) {
				doClusteringEnded(event.getClusteringResults());
			}
		});
		
		eventBus.addHandler(ActionFailedEvent.TYPE, new ActionFailedEventHandler() {
			@Override
			public void onActionFailed(ActionFailedEvent event) {
				doActionFailed(event.getMessage());
			}
		});
	}
	
	private void doClusterStrategyChosen(ClusteringMethod selectedClusteringMethod) {
		History.newItem(selectedClusteringMethod.name());
	}
	
	private void doReadyForClustering(List<Clusterable> clusterElements) {
		this.clusterElements = clusterElements;
		History.newItem("readyForClustering");
	}
	
	private void doClusteringEnded(List<Clusterable> clusteringResults) {
		this.clusteringResults = clusteringResults;
		History.newItem("clusteringEnded");
	}
	
	private void doActionFailed(String message) {
		Window.alert(message);
		
		History.newItem("clusterStrategyChoice");
	}
	
	@Override
	public void go(final HasWidgets container) {
		this.container = container;
		
		if ("".equals(History.getToken())) {
			History.newItem("clusterStrategyChoice");
		} else {
			History.fireCurrentHistoryState();
		}
	}
	
	@Override
	public void onValueChange(ValueChangeEvent<String> event) {
		String token = event.getValue();
		
		if (token != null) {
			Presenter presenter = null;
			
			if (token.equals("clusterStrategyChoice")) {
				presenter = new ClusterStrategyChoicePresenter(eventBus, new ClusterStrategyChoiceView());
			} else if (token.equals("readyForClustering")) {
				if (selectedClusteringMethod != null && clusterElements != null && clusterElements.size() > 0) {
					presenter = new ReadyForClusteringPresenter(rpcService, eventBus, new ReadyForClusteringView(), selectedClusteringMethod, clusterElements);
				} else {
					History.newItem("clusterStrategyChoice");
				}
			} else if (token.equals("clusteringEnded")) {
				if (selectedClusteringMethod != null && clusteringResults != null && clusteringResults.size() > 0) {
					presenter = new ClusteringEndedPresenter(rpcService, eventBus, new ClusteringEndedView(selectedClusteringMethod.getClusteringType()), accessToken, clusteringResults);
				} else {
					History.newItem("clusterStrategyChoice");
				}
			} else {			
				for (ClusteringMethod method: ClusteringMethod.values()) {
					if (method.name().equals(token)) {
						selectedClusteringMethod = method;
						if (clusterElements != null && clusterElements.size() > 0) {
							presenter = new ReadyForClusteringPresenter(rpcService, eventBus, new ReadyForClusteringView(), selectedClusteringMethod, clusterElements);
						} else {
							presenter = new ClusterStrategyChosenPresenter(rpcService, eventBus, new ClusterStrategyChosenView(), accessToken);
						}
						break;
					}
				}
			}
			
			if (presenter != null) {
				presenter.go(container);
			}
		}
	}
	
}
